#!/usr/bin/env python3

import os
import sys

from graphlib import TopologicalSorter

MYDIR = os.path.dirname(os.path.abspath(__file__))


def extract_all(dstdir, fin=sys.stdin):
    pkg = None
    prev_pkg = None
    start_marker = '# RECIPE START'
    end_marker = '# RECIPE END'
    depends_marker = '# depends:'
    fout = None
    recipe_path = None
    tmp_recipe_path = None
    mypid = os.getpid()
    deps = []
    graph = {}

    def prnt(what):
        print(what, file=fout, end='')

    for line in fin:
        stripped_line = line.strip()
        if stripped_line.startswith(start_marker):
            prev_pkg = pkg
            pkg = stripped_line.split(start_marker)[1].strip()
            assert fout is None
            recipe_path = os.path.join(dstdir, pkg + '.sh')
            tmp_recipe_path = f'{recipe_path}.{mypid}'
            fout = open(tmp_recipe_path, 'wt')
            mk_header(pkg, fout)
            prnt(line)
        elif stripped_line.startswith(end_marker):
            prnt(line)
            assert fout is not None
            assert recipe_path is not None
            os.fchmod(fout.fileno(), 0o755)
            fout.close()
            fout = None
            graph[pkg] = set(deps)
            deps = []
            os.rename(tmp_recipe_path, recipe_path)
        elif stripped_line.startswith(depends_marker):
            prnt(line)
            req_pkg = stripped_line.split(depends_marker)[1].strip()
            deps.append(req_pkg)
        elif len(stripped_line) == 0 and fout is None:
            # skip empty lines between recipes
            continue
        else:
            prnt(line)

    assert fout is None
    ts = TopologicalSorter(graph)
    sortedPkgs = list(ts.static_order())
    with open(os.path.join(dstdir, "graph.py"), 'wt') as gf:
        gf.write("PACKAGES = ")
        gf.write(repr(graph))
        gf.write('\n')
        gf.write('SORTED_PACKAGES = ')
        gf.write(repr(sortedPkgs))
        gf.write('\n')


def extract_body(pkg, fin=sys.stdin, fout=sys.stdout):
    """extract recipe for @var{pkg} and print it to @var{fout}"""
    started = False
    start_marker = f'# RECIPE START {pkg}'
    end_marker = f'# RECIPE END {pkg}'
    dependency_marker = '# depends:'

    def prnt(line):
        print(line, file=fout, end='')

    def emit_dependency(line):
        _, dep = line.strip().split(dependency_marker)
        prnt(line)
        prnt(dep.strip())

    for line in fin:
        stripped_line = line.strip()
        if not started:
            if stripped_line == start_marker:
                started = True
                prnt(line)
        elif stripped_line == end_marker:
                prnt(line)
                return
        elif stripped_line.startswith(dependency_marker):
                emit_dependency(line)
        else:
            prnt(line)


HEADER = r"""#!/bin/bash
set -e
set -x
MYDIR="${0%/*}"
cd "$MYDIR/.."
source "recipes/common.sh"

"""

SETTINGS_HEADER = r"""#!/bin/echo this scriptlet should be sourced by a build recipe
"""


def mk_header(pkg, fout=sys.stdout):
    if pkg == "common":
        print(SETTINGS_HEADER, file=fout)
    else:
        print(HEADER, file=fout)


def main():
    recipes_dir = os.path.join(MYDIR, 'recipes')
    os.makedirs(recipes_dir, exist_ok=True)
    extract_all(recipes_dir)


if __name__ == '__main__':
    main()
